1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/industry_fsm_sale/models/project_project.py
2024-12-10 09:04:09 +07:00

183 lines
8.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
from odoo.osv import expression
from odoo.tools import SQL
class Project(models.Model):
_inherit = "project.project"
allow_material = fields.Boolean("Products on Tasks", compute="_compute_allow_material", store=True, readonly=False)
allow_quotations = fields.Boolean(
"Extra Quotations", compute="_compute_allow_quotations", store=True, readonly=False)
allow_billable = fields.Boolean(
compute='_compute_allow_billable', store=True, readonly=False)
sale_line_id = fields.Many2one(
compute="_compute_sale_line_id", store=True, readonly=False)
_sql_constraints = [
('material_imply_billable', "CHECK((allow_material = 't' AND allow_billable = 't') OR (allow_material = 'f'))", 'The material can be allowed only when the task can be billed.'),
('fsm_imply_task_rate', "CHECK((is_fsm = 't' AND sale_line_id IS NULL) OR (is_fsm = 'f'))", 'An FSM project must be billed at task rate or employee rate.'),
('timesheet_product_required_if_billable_and_time', """
CHECK(
(allow_billable = 't' AND allow_timesheets = 't' AND is_fsm = 't' AND timesheet_product_id IS NOT NULL)
OR (allow_billable IS NOT TRUE)
OR (allow_timesheets IS NOT TRUE)
OR (is_fsm IS NOT TRUE)
OR (allow_billable IS NULL)
OR (allow_timesheets IS NULL)
OR (is_fsm IS NULL)
)""", 'The timesheet product is required when the fsm project can be billed and timesheets are allowed.'),
]
def _get_hide_partner(self):
return super()._get_hide_partner() and not self.is_fsm
@api.model
def default_get(self, fields_list):
defaults = super().default_get(fields_list)
if 'allow_quotations' in fields_list and 'allow_quotations' not in defaults and defaults.get('is_fsm'):
defaults['allow_quotations'] = self.env.user.has_group('industry_fsm.group_fsm_quotation_from_task')
return defaults
@api.depends('is_fsm')
def _compute_allow_quotations(self):
if not self.env.user.has_group('industry_fsm.group_fsm_quotation_from_task'):
self.allow_quotations = False
else:
for project in self:
project.allow_quotations = project.is_fsm
@api.depends('is_fsm', 'allow_material')
def _compute_allow_billable(self):
for project in self:
project.allow_billable = project.allow_billable or project.is_fsm or project.allow_material
@api.depends('allow_billable', 'is_fsm')
def _compute_allow_material(self):
for project in self:
project.allow_material = project.allow_billable and project.is_fsm
def flush_model(self, fnames=None):
if fnames is not None:
# force 'allow_billable' and 'allow_material' to be flushed
# altogether in order to satisfy the SQL constraint above
fnames = set(fnames)
if 'allow_billable' in fnames or 'allow_material' in fnames:
fnames.add('allow_billable')
fnames.add('allow_material')
return super().flush_model(fnames)
def flush_recordset(self, fnames=None):
if fnames is not None:
# force 'allow_billable' and 'allow_material' to be flushed
# altogether in order to satisfy the SQL constraint above
fnames = set(fnames)
if 'allow_billable' in fnames or 'allow_material' in fnames:
fnames.add('allow_billable')
fnames.add('allow_material')
return super().flush_recordset(fnames)
@api.depends('sale_line_id', 'sale_line_employee_ids', 'allow_billable', 'is_fsm')
def _compute_pricing_type(self):
fsm_projects = self.filtered(lambda project: project.allow_billable and project.is_fsm)
for fsm_project in fsm_projects:
if fsm_project.sale_line_employee_ids:
fsm_project.update({'pricing_type': 'employee_rate'})
else:
fsm_project.update({'pricing_type': 'task_rate'})
super(Project, self - fsm_projects)._compute_pricing_type()
def _search_pricing_type(self, operator, value):
domain = super()._search_pricing_type(operator, value)
if value == 'fixed_rate':
fsm_domain = [('is_fsm', operator, False)]
if operator == '=':
domain = expression.AND([fsm_domain, domain])
else:
domain = expression.OR([fsm_domain, domain])
elif value in ['task_rate', 'employee_rate']:
fsm_domain = [
('is_fsm', '=', True),
('allow_billable', '=', True),
('sale_line_employee_ids', '!=' if value == 'employee_rate' else '=', False),
]
if operator == '=':
domain = expression.OR([fsm_domain, domain])
else:
fsm_domain = expression.normalize_domain(fsm_domain)
fsm_domain.insert(0, expression.NOT_OPERATOR)
domain = expression.AND([expression.distribute_not(fsm_domain), domain])
return domain
@api.depends('is_fsm')
def _compute_sale_line_id(self):
# We cannot have a SOL in the fsm project
fsm_projects = self.filtered('is_fsm')
fsm_projects.update({'sale_line_id': False})
super(Project, self - fsm_projects)._compute_sale_line_id()
@api.depends('sale_line_employee_ids.sale_line_id', 'sale_line_id')
def _compute_partner_id(self):
basic_projects = self.filtered(lambda project: not project.is_fsm)
super(Project, basic_projects)._compute_partner_id()
@api.depends('is_fsm')
def _compute_display_sales_stat_buttons(self):
fsm_projects = self.filtered('is_fsm')
fsm_projects.display_sales_stat_buttons = False
super(Project, self - fsm_projects)._compute_display_sales_stat_buttons()
def _get_profitability_sale_order_items_domain(self, domain=None):
quotation_projects = self.filtered('allow_quotations')
if quotation_projects:
include_additional_sale_orders = [
('order_id', 'in', quotation_projects._get_additional_quotations([
('state', '=', 'sale'),
]).ids)
]
domain = include_additional_sale_orders \
if domain is None \
else expression.OR([domain, include_additional_sale_orders])
return super()._get_profitability_sale_order_items_domain(domain)
def _get_additional_quotations_query(self, domain=None):
if domain is None:
domain = []
SaleOrder = self.env['sale.order']
query = SaleOrder._where_calc(expression.AND([domain, [('task_id', '!=', False)]]))
SaleOrder._apply_ir_rules(query, 'read')
task_alias = query.make_alias(SaleOrder._table, 'task_id')
query.add_join("JOIN", task_alias, 'project_task', SQL(
"%s = %s AND %s IN %s",
SQL.identifier(SaleOrder._table, 'task_id'),
SQL.identifier(task_alias, 'id'),
SQL.identifier(task_alias, 'project_id'),
tuple(self.ids),
))
return query
def _get_additional_quotations(self, domain=None):
return self.env['sale.order'].browse(self._get_additional_quotations_query(domain))
def _get_sale_order_items_query(self, domain_per_model=None):
basic_project_domain = [('is_fsm', '=', False)] # when the project is a fsm one, no SOL is linked to that project.
employee_mapping_domain = [('project_id.is_fsm', '=', False)]
if domain_per_model is None:
domain_per_model = {
'project.project': basic_project_domain,
'project.sale.line.employee.map': employee_mapping_domain,
}
else:
domain_per_model['project.project'] = expression.AND([
domain_per_model.get('project.project', []),
basic_project_domain,
])
domain_per_model['project.sale.line.employee.map'] = expression.AND([
domain_per_model.get('project.sale.line.employee.map', []),
employee_mapping_domain,
])
return super()._get_sale_order_items_query(domain_per_model)