diff --git a/product_contract/models/sale_order.py b/product_contract/models/sale_order.py index 0832b7b1b..70835795c 100644 --- a/product_contract/models/sale_order.py +++ b/product_contract/models/sale_order.py @@ -25,20 +25,37 @@ class SaleOrder(models.Model): _("You can't upsell or downsell a terminated contract") ) + def _get_line_to_create_contract(self): + """ + Override this method to define more filter criteria of line for which we create contract + :return: line to create contract + """ + self.ensure_one() + line_to_create_contract = self.order_line.filtered( + lambda r: not r.contract_id and r.is_contract + ) + return line_to_create_contract + + def _get_line_to_update_contract(self): + """ + Override this method to define more filter criteria of line for which we update contract + :return: line to update contract + """ + self.ensure_one() + line_to_update_contract = self.order_line.filtered( + lambda r: r.contract_id + and r.is_contract + and r not in r.contract_id.contract_line_ids.mapped("sale_order_line_id") + ) + return line_to_update_contract + @api.depends("order_line.contract_id", "state") def _compute_need_contract_creation(self): self.update({"need_contract_creation": False}) for rec in self: if rec.state in ("sale", "done"): - line_to_create_contract = rec.order_line.filtered( - lambda r: not r.contract_id and r.product_id.is_contract - ) - line_to_update_contract = rec.order_line.filtered( - lambda r: r.contract_id - and r.product_id.is_contract - and r - not in r.contract_id.contract_line_ids.mapped("sale_order_line_id") - ) + line_to_create_contract = rec._get_line_to_create_contract() + line_to_update_contract = rec._get_line_to_update_contract() if line_to_create_contract or line_to_update_contract: rec.need_contract_creation = True @@ -67,11 +84,11 @@ class SaleOrder(models.Model): contracts = [] for rec in self.filtered("is_contract"): line_to_create_contract = rec.order_line.filtered( - lambda r: not r.contract_id and r.product_id.is_contract + lambda r: not r.contract_id and r.is_contract ) line_to_update_contract = rec.order_line.filtered( lambda r: r.contract_id - and r.product_id.is_contract + and r.is_contract and r not in r.contract_id.contract_line_ids.mapped("sale_order_line_id") ) diff --git a/product_contract/models/sale_order_line.py b/product_contract/models/sale_order_line.py index 038dd6d6f..0a4a190d4 100644 --- a/product_contract/models/sale_order_line.py +++ b/product_contract/models/sale_order_line.py @@ -12,7 +12,7 @@ class SaleOrderLine(models.Model): _inherit = "sale.order.line" is_contract = fields.Boolean( - string="Is a contract", related="product_id.is_contract" + string="Is a contract", ) contract_id = fields.Many2one( comodel_name="contract.contract", string="Contract", copy=False @@ -120,10 +120,10 @@ class SaleOrderLine(models.Model): ) return date_end - @api.depends("product_id") + @api.depends("product_id", "is_contract") def _compute_auto_renew(self): for rec in self: - if rec.product_id.is_contract: + if rec.is_contract: rec.product_uom_qty = rec.product_id.default_qty rec.recurring_rule_type = rec.product_id.recurring_rule_type rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type @@ -135,11 +135,21 @@ class SaleOrderLine(models.Model): rec.auto_renew_interval = rec.product_id.auto_renew_interval rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type - @api.onchange("date_start", "product_uom_qty", "recurring_rule_type") + @api.onchange("date_start", "product_uom_qty", "recurring_rule_type", "is_contract") def onchange_date_start(self): - for rec in self.filtered("product_id.is_contract"): + for rec in self.filtered("is_contract"): rec.date_end = rec._get_date_end() if rec.date_start else False + @api.onchange("product_id") + def onchange_product(self): + super().onchange_product() + for rec in self: + if rec.product_id.is_contract: + rec.is_contract = True + else: + # Don't initialize wrong values + rec.is_contract = False + def _get_contract_line_qty(self): """Returns the quantity to be put on new contract lines.""" self.ensure_one() @@ -259,6 +269,16 @@ class SaleOrderLine(models.Model): _("Contract product has different contract template") ) + @api.constrains("product_id", "contract_id") + def _check_contract_sale_contract_template(self): + for rec in self: + if rec.is_contract and not rec.product_id.is_contract: + raise ValidationError( + _( + 'You can check the field "Is a contract" only for Contract product' + ) + ) + def _compute_invoice_status(self): res = super()._compute_invoice_status() self.filtered("contract_id").update({"invoice_status": "no"}) @@ -274,12 +294,12 @@ class SaleOrderLine(models.Model): "qty_delivered", "product_uom_qty", "order_id.state", - "product_id.is_contract", + "is_contract", ) def _get_to_invoice_qty(self): """ sale line linked to contracts must not be invoiced from sale order """ res = super()._get_to_invoice_qty() - self.filtered("product_id.is_contract").update({"qty_to_invoice": 0.0}) + self.filtered("is_contract").update({"qty_to_invoice": 0.0}) return res