diff --git a/product_contract/models/sale_order.py b/product_contract/models/sale_order.py index 6ab44cdb24..e4f673d966 100644 --- a/product_contract/models/sale_order.py +++ b/product_contract/models/sale_order.py @@ -48,8 +48,11 @@ def _compute_is_contract(self): def _prepare_contract_value(self, contract_template): self.ensure_one() + name = ( + f"{contract_template.name}: {self.name}" if contract_template else self.name + ) return { - "name": f"{contract_template.name}: {self.name}", + "name": name, "partner_id": self.partner_id.id, "company_id": self.company_id.id, "contract_template_id": contract_template.id, @@ -63,6 +66,7 @@ def _prepare_contract_value(self, contract_template): def action_create_contract(self): contract_model = self.env["contract.contract"] contracts = [] + lines_without_contract = self.env["sale.order.line"] 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 @@ -80,17 +84,8 @@ def action_create_contract(self): rec.company_id ).property_contract_template_id if not contract_template: - raise ValidationError( - _( - "You must specify a contract " - "template for '%(product_name)s' product " - "in '%(company_name)s' company." - ) - % { - "product_name": order_line.product_id.name, - "company_name": rec.company_id.name, - } - ) + lines_without_contract |= order_line + continue contract_templates |= contract_template for contract_template in contract_templates: order_lines = line_to_create_contract.filtered( @@ -109,6 +104,15 @@ def action_create_contract(self): order_lines.write({"contract_id": contract.id}) for line in line_to_update_contract: line.create_contract_line(line.contract_id) + if lines_without_contract: + contract = contract_model.create( + rec._prepare_contract_value(self.env["contract.template"]) + ) + contracts.append(contract.id) + contract._onchange_contract_template_id() + contract._onchange_contract_type() + lines_without_contract.create_contract_line(contract) + lines_without_contract.write({"contract_id": contract.id}) return contract_model.browse(contracts) def action_confirm(self): diff --git a/product_contract/tests/test_sale_order.py b/product_contract/tests/test_sale_order.py index 434f54a5c2..4cbcbc7748 100644 --- a/product_contract/tests/test_sale_order.py +++ b/product_contract/tests/test_sale_order.py @@ -6,7 +6,7 @@ from freezegun import freeze_time from odoo import fields -from odoo.exceptions import UserError, ValidationError +from odoo.exceptions import ValidationError from odoo.fields import Date from odoo.tests.common import TransactionCase @@ -127,9 +127,8 @@ def test_change_sale_company(self): other_company = self.env["res.company"].create( {"name": "other company", "parent_id": self.sale.company_id.id} ) - with self.assertRaises(UserError): - self.sale.company_id = other_company - self.sale.action_confirm() + self.sale.company_id = other_company + self.assertFalse(self.sale.order_line.mapped("contract_template_id")) def test_change_sale_company_2(self): """Contract company must be the sale order company.""" @@ -374,6 +373,63 @@ def test_order_lines_with_the_same_contract_template(self): ) self.assertEqual(len(contracts), 1) + def test_order_lines_without_contract_template(self): + """It should create one contract with lines without contract + template""" + self.product1.with_company(self.sale.company_id).write( + {"is_contract": True, "property_contract_template_id": False} + ) + self.product2.with_company(self.sale.company_id).write( + {"is_contract": True, "property_contract_template_id": False} + ) + self.sale.order_line._compute_auto_renew() + self.assertFalse(self.sale.order_line.mapped("contract_template_id")) + self.sale.action_confirm() + contracts = self.sale.order_line.mapped("contract_id") + self.assertEqual(len(contracts), 1) + self.assertEqual(len(contracts.contract_line_ids), 2) + self.assertEqual(contracts.name, self.sale.name) + contracts = ( + self.env["contract.line"] + .search([("sale_order_line_id", "in", self.sale.order_line.ids)]) + .mapped("contract_id") + ) + self.assertEqual(len(contracts), 1) + + def test_order_lines_without_contract_template2(self): + """It should create two contracts + product1 with contract template + product2 without contract template + """ + self.product2.with_company(self.sale.company_id).write( + {"is_contract": True, "property_contract_template_id": False} + ) + self.sale.order_line._compute_auto_renew() + line_product_1 = self.sale.order_line.filtered( + lambda line: line.product_id == self.product1 + ) + line_product_2 = self.sale.order_line.filtered( + lambda line: line.product_id == self.product2 + ) + self.assertEqual(line_product_1.contract_template_id, self.contract_template1) + self.assertFalse(line_product_2.contract_template_id) + self.sale.action_confirm() + contracts = self.sale.order_line.mapped("contract_id") + self.assertEqual(len(contracts), 2) + self.assertEqual(len(line_product_1.contract_id.contract_line_ids), 1) + self.assertEqual(len(line_product_2.contract_id.contract_line_ids), 1) + self.assertEqual( + line_product_1.contract_id.name, + f"{self.contract_template1.name}: {self.sale.name}", + ) + self.assertEqual(line_product_2.contract_id.name, self.sale.name) + contracts = ( + self.env["contract.line"] + .search([("sale_order_line_id", "in", self.sale.order_line.ids)]) + .mapped("contract_id") + ) + self.assertEqual(len(contracts), 2) + def _create_contract_product( self, recurring_rule_type, contract_start_date_method, force_month=False ):