diff options
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/sale_timesheet/__manifest__.py | 1 | ||||
| -rw-r--r-- | addons/sale_timesheet/data/sale_service_data.xml | 12 | ||||
| -rw-r--r-- | addons/sale_timesheet/models/project.py | 45 | ||||
| -rw-r--r-- | addons/sale_timesheet/static/img/product_product_time_product.png | bin | 0 -> 5370 bytes | |||
| -rw-r--r-- | addons/sale_timesheet/views/project_task_views.xml | 27 | ||||
| -rw-r--r-- | addons/sale_timesheet/wizard/project_create_sale_order.py | 3 | ||||
| -rw-r--r-- | addons/sale_timesheet/wizard/project_task_create_sale_order.py | 3 |
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 Binary files differnew file mode 100644 index 00000000000..c9d7a77d4f5 --- /dev/null +++ b/addons/sale_timesheet/static/img/product_product_time_product.png 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': ['&', ('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': ['&', ('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) |
