summaryrefslogtreecommitdiff
path: root/addons/sale_timesheet/models/product.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/sale_timesheet/models/product.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/sale_timesheet/models/product.py')
-rw-r--r--addons/sale_timesheet/models/product.py136
1 files changed, 136 insertions, 0 deletions
diff --git a/addons/sale_timesheet/models/product.py b/addons/sale_timesheet/models/product.py
new file mode 100644
index 00000000..3d6e0766
--- /dev/null
+++ b/addons/sale_timesheet/models/product.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import threading
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+
+
+class ProductTemplate(models.Model):
+ _inherit = 'product.template'
+
+ service_policy = fields.Selection([
+ ('ordered_timesheet', 'Prepaid'),
+ ('delivered_timesheet', 'Timesheets on tasks'),
+ ('delivered_manual', 'Milestones (manually set quantities on order)')
+ ], string="Service Invoicing Policy", compute='_compute_service_policy', inverse='_inverse_service_policy')
+ service_type = fields.Selection(selection_add=[
+ ('timesheet', 'Timesheets on project (one fare per SO/Project)'),
+ ], ondelete={'timesheet': 'set default'})
+ # override domain
+ project_id = fields.Many2one(domain="[('company_id', '=', current_company_id), ('allow_billable', '=', True), ('bill_type', '=', 'customer_task'), ('allow_timesheets', 'in', [service_policy == 'delivered_timesheet', True])]")
+ project_template_id = fields.Many2one(domain="[('company_id', '=', current_company_id), ('allow_billable', '=', True), ('bill_type', '=', 'customer_project'), ('allow_timesheets', 'in', [service_policy == 'delivered_timesheet', True])]")
+
+ def _default_visible_expense_policy(self):
+ visibility = self.user_has_groups('project.group_project_user')
+ return visibility or super(ProductTemplate, self)._default_visible_expense_policy()
+
+ def _compute_visible_expense_policy(self):
+ visibility = self.user_has_groups('project.group_project_user')
+ for product_template in self:
+ if not product_template.visible_expense_policy:
+ product_template.visible_expense_policy = visibility
+ return super(ProductTemplate, self)._compute_visible_expense_policy()
+
+ @api.depends('invoice_policy', 'service_type')
+ def _compute_service_policy(self):
+ for product in self:
+ policy = None
+ if product.invoice_policy == 'delivery':
+ policy = 'delivered_manual' if product.service_type == 'manual' else 'delivered_timesheet'
+ elif product.invoice_policy == 'order' and (product.service_type == 'timesheet' or product.type == 'service'):
+ policy = 'ordered_timesheet'
+ product.service_policy = policy
+
+ def _inverse_service_policy(self):
+ for product in self:
+ policy = product.service_policy
+ if not policy and not product.invoice_policy =='delivery':
+ product.invoice_policy = 'order'
+ product.service_type = 'manual'
+ elif policy == 'ordered_timesheet':
+ product.invoice_policy = 'order'
+ product.service_type = 'timesheet'
+ else:
+ product.invoice_policy = 'delivery'
+ product.service_type = 'manual' if policy == 'delivered_manual' else 'timesheet'
+
+ @api.onchange('type')
+ def _onchange_type(self):
+ res = super(ProductTemplate, self)._onchange_type()
+ if self.type == 'service' and not self.invoice_policy:
+ self.invoice_policy = 'order'
+ self.service_type = 'timesheet'
+ elif self.type == 'service' and self.invoice_policy == 'order':
+ self.service_policy = 'ordered_timesheet'
+ elif self.type == 'consu' and not self.invoice_policy and self.service_policy == 'ordered_timesheet':
+ self.invoice_policy = 'order'
+ return res
+
+ @api.model
+ def _get_onchange_service_policy_updates(self, service_tracking, service_policy, project_id, project_template_id):
+ vals = {}
+ if service_tracking != 'no' and service_policy == 'delivered_timesheet':
+ if project_id and not project_id.allow_timesheets:
+ vals['project_id'] = False
+ elif project_template_id and not project_template_id.allow_timesheets:
+ vals['project_template_id'] = False
+ return vals
+
+ @api.onchange('service_policy')
+ def _onchange_service_policy(self):
+ vals = self._get_onchange_service_policy_updates(self.service_tracking,
+ self.service_policy,
+ self.project_id,
+ self.project_template_id)
+ if vals:
+ self.update(vals)
+
+ def unlink(self):
+ time_product = self.env.ref('sale_timesheet.time_product')
+ if time_product.product_tmpl_id in self:
+ raise ValidationError(_('The %s product is required by the Timesheet app and cannot be archived/deleted.') % time_product.name)
+ return super(ProductTemplate, self).unlink()
+
+ def write(self, vals):
+ # timesheet product can't be archived
+ test_mode = getattr(threading.currentThread(), 'testing', False) or self.env.registry.in_test_mode()
+ if not test_mode and 'active' in vals and not vals['active']:
+ time_product = self.env.ref('sale_timesheet.time_product')
+ if time_product.product_tmpl_id in self:
+ raise ValidationError(_('The %s product is required by the Timesheet app and cannot be archived/deleted.') % time_product.name)
+ return super(ProductTemplate, self).write(vals)
+
+
+class ProductProduct(models.Model):
+ _inherit = 'product.product'
+
+ def _is_delivered_timesheet(self):
+ """ Check if the product is a delivered timesheet """
+ self.ensure_one()
+ return self.type == 'service' and self.service_policy == 'delivered_timesheet'
+
+ @api.onchange('service_policy')
+ def _onchange_service_policy(self):
+ vals = self.product_tmpl_id._get_onchange_service_policy_updates(self.service_tracking,
+ self.service_policy,
+ self.project_id,
+ self.project_template_id)
+ if vals:
+ self.update(vals)
+
+ def unlink(self):
+ time_product = self.env.ref('sale_timesheet.time_product')
+ if time_product in self:
+ raise ValidationError(_('The %s product is required by the Timesheet app and cannot be archived/deleted.') % time_product.name)
+ return super(ProductProduct, self).unlink()
+
+ def write(self, vals):
+ # timesheet product can't be archived
+ test_mode = getattr(threading.currentThread(), 'testing', False) or self.env.registry.in_test_mode()
+ if not test_mode and 'active' in vals and not vals['active']:
+ time_product = self.env.ref('sale_timesheet.time_product')
+ if time_product in self:
+ raise ValidationError(_('The %s product is required by the Timesheet app and cannot be archived/deleted.') % time_product.name)
+ return super(ProductProduct, self).write(vals)