diff --git a/product_contract/models/contract_line.py b/product_contract/models/contract_line.py index 3f81bc201..91c08480a 100644 --- a/product_contract/models/contract_line.py +++ b/product_contract/models/contract_line.py @@ -35,15 +35,19 @@ class ContractLine(models.Model): for rec in self: rec.date_start = fields.Date.today() if rec.product_id.is_contract: - rec.recurring_rule_type = rec.product_id.recurring_rule_type - rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type - rec.recurring_interval = 1 - rec.is_auto_renew = rec.product_id.is_auto_renew - rec.auto_renew_interval = rec.product_id.auto_renew_interval - rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type - rec.termination_notice_interval = ( - rec.product_id.termination_notice_interval - ) - rec.termination_notice_rule_type = ( - rec.product_id.termination_notice_rule_type + rec.update( + { + "recurring_rule_type": rec.product_id.recurring_rule_type, + "recurring_invoicing_type": rec.product_id.recurring_invoicing_type, + "recurring_interval": 1, + "is_auto_renew": rec.product_id.is_auto_renew, + "auto_renew_interval": rec.product_id.auto_renew_interval, + "auto_renew_rule_type": rec.product_id.auto_renew_rule_type, + "termination_notice_interval": ( + rec.product_id.termination_notice_interval + ), + "termination_notice_rule_type": ( + rec.product_id.termination_notice_rule_type + ), + } ) diff --git a/product_contract/models/sale_order.py b/product_contract/models/sale_order.py index 44ffd41a7..0832b7b1b 100644 --- a/product_contract/models/sale_order.py +++ b/product_contract/models/sale_order.py @@ -14,7 +14,7 @@ class SaleOrder(models.Model): need_contract_creation = fields.Boolean(compute="_compute_need_contract_creation") @api.constrains("state") - def check_contact_is_not_terminated(self): + def _check_contact_is_not_terminated(self): for rec in self: if rec.state not in ( "sale", @@ -27,8 +27,8 @@ class SaleOrder(models.Model): @api.depends("order_line.contract_id", "state") def _compute_need_contract_creation(self): + self.update({"need_contract_creation": False}) for rec in self: - rec.need_contract_creation = False 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 @@ -64,7 +64,7 @@ class SaleOrder(models.Model): def action_create_contract(self): contract_model = self.env["contract.contract"] - contracts = self.env["contract.contract"] + 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 @@ -98,14 +98,14 @@ class SaleOrder(models.Model): contract = contract_model.create( rec._prepare_contract_value(contract_template) ) - contracts |= contract + contracts.append(contract) contract._onchange_contract_template_id() contract._onchange_contract_type() order_lines.create_contract_line(contract) order_lines.write({"contract_id": contract.id}) for line in line_to_update_contract: line.create_contract_line(line.contract_id) - return contracts + return contract_model.browse(contracts) def action_confirm(self): """If we have a contract in the order, set it up""" @@ -117,19 +117,22 @@ class SaleOrder(models.Model): @api.depends("order_line") def _compute_contract_count(self): for rec in self: - rec.contract_count = len( - rec.order_line.mapped("contract_id").filtered(lambda r: r.active) - ) + rec.contract_count = len(rec.order_line.mapped("contract_id")) def action_show_contracts(self): self.ensure_one() - action = self.env.ref("contract.action_customer_contract").sudo().read()[0] + action = self.env["ir.actions.act_window"]._for_xml_id( + "contract.action_customer_contract" + ) + contracts = ( self.env["contract.line"] .search([("sale_order_line_id", "in", self.order_line.ids)]) .mapped("contract_id") ) - action["domain"] = [("id", "in", contracts.ids)] + action["domain"] = [ + ("contract_line_ids.sale_order_line_id", "in", self.order_line.ids) + ] if len(contracts) == 1: # If there is only one contract, open it directly action.update( diff --git a/product_contract/models/sale_order_line.py b/product_contract/models/sale_order_line.py index 6c261036e..038dd6d6f 100644 --- a/product_contract/models/sale_order_line.py +++ b/product_contract/models/sale_order_line.py @@ -52,10 +52,19 @@ class SaleOrderLine(models.Model): required=False, copy=False, ) - is_auto_renew = fields.Boolean(string="Auto Renew", default=False) + is_auto_renew = fields.Boolean( + string="Auto Renew", + compute="_compute_auto_renew", + default=False, + store=True, + readonly=False, + ) auto_renew_interval = fields.Integer( default=1, string="Renew Every", + compute="_compute_auto_renew", + store=True, + readonly=False, help="Renew every (Days/Week/Month/Year)", ) auto_renew_rule_type = fields.Selection( @@ -66,12 +75,15 @@ class SaleOrderLine(models.Model): ("yearly", "Year(s)"), ], default="yearly", + compute="_compute_auto_renew", + store=True, + readonly=False, string="Renewal type", help="Specify Interval for automatic renewal.", ) @api.constrains("contract_id") - def check_contact_is_not_terminated(self): + def _check_contact_is_not_terminated(self): for rec in self: if ( rec.order_id.state not in ("sale", "done", "cancel") @@ -108,8 +120,8 @@ class SaleOrderLine(models.Model): ) return date_end - @api.onchange("product_id") - def onchange_product(self): + @api.depends("product_id") + def _compute_auto_renew(self): for rec in self: if rec.product_id.is_contract: rec.product_uom_qty = rec.product_id.default_qty @@ -248,9 +260,8 @@ class SaleOrderLine(models.Model): ) def _compute_invoice_status(self): - res = super(SaleOrderLine, self)._compute_invoice_status() - for line in self.filtered("contract_id"): - line.invoice_status = "no" + res = super()._compute_invoice_status() + self.filtered("contract_id").update({"invoice_status": "no"}) return res def invoice_line_create(self, invoice_id, qty): diff --git a/product_contract/tests/test_product.py b/product_contract/tests/test_product.py index 66770a409..0d06b6506 100644 --- a/product_contract/tests/test_product.py +++ b/product_contract/tests/test_product.py @@ -3,15 +3,23 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo.exceptions import ValidationError -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase -class TestProductTemplate(TransactionCase): - def setUp(self): - super(TestProductTemplate, self).setUp() - self.service_product = self.env.ref("product.product_product_1") - self.consu_product = self.env.ref("product.product_product_5") - self.contract = self.env["contract.template"].create({"name": "Test"}) +class TestProductTemplate(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, + tracking_disable=True, + no_reset_password=True, + ) + ) + cls.service_product = cls.env.ref("product.product_product_1") + cls.consu_product = cls.env.ref("product.product_product_5") + cls.contract = cls.env["contract.template"].create({"name": "Test"}) def test_change_is_contract(self): """It should verify that the property_contract_template_id diff --git a/product_contract/tests/test_sale_order.py b/product_contract/tests/test_sale_order.py index 9d42152c9..804863f99 100644 --- a/product_contract/tests/test_sale_order.py +++ b/product_contract/tests/test_sale_order.py @@ -6,19 +6,27 @@ from dateutil.relativedelta import relativedelta from odoo.exceptions import UserError, ValidationError from odoo.fields import Date -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase -class TestSaleOrder(TransactionCase): - def setUp(self): - super(TestSaleOrder, self).setUp() - self.product1 = self.env.ref("product.product_product_1") - self.product2 = self.env.ref("product.product_product_2") - self.sale = self.env.ref("sale.sale_order_2") - self.contract_template1 = self.env["contract.template"].create( +class TestSaleOrder(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, + tracking_disable=True, + no_reset_password=True, + ) + ) + cls.product1 = cls.env.ref("product.product_product_1") + cls.product2 = cls.env.ref("product.product_product_2") + cls.sale = cls.env.ref("sale.sale_order_2") + cls.contract_template1 = cls.env["contract.template"].create( {"name": "Template 1"} ) - self.contract_template2 = self.env["contract.template"].create( + cls.contract_template2 = cls.env["contract.template"].create( { "name": "Template 2", "contract_line_ids": [ @@ -26,10 +34,10 @@ class TestSaleOrder(TransactionCase): 0, 0, { - "product_id": self.product2.id, + "product_id": cls.product2.id, "name": "Services from #START# to #END#", "quantity": 1, - "uom_id": self.product2.uom_id.id, + "uom_id": cls.product2.uom_id.id, "price_unit": 100, "discount": 50, "recurring_rule_type": "yearly", @@ -39,44 +47,44 @@ class TestSaleOrder(TransactionCase): ], } ) - self.product1.with_company(self.sale.company_id).write( + cls.product1.with_company(cls.sale.company_id).write( { "is_contract": True, "default_qty": 12, "recurring_rule_type": "monthlylastday", "recurring_invoicing_type": "post-paid", - "property_contract_template_id": self.contract_template1.id, + "property_contract_template_id": cls.contract_template1.id, } ) - self.product2.with_company(self.sale.company_id).write( + cls.product2.with_company(cls.sale.company_id).write( { "is_contract": True, - "property_contract_template_id": self.contract_template2.id, + "property_contract_template_id": cls.contract_template2.id, } ) - self.order_line1 = self.sale.order_line.filtered( - lambda l: l.product_id == self.product1 + cls.order_line1 = cls.sale.order_line.filtered( + lambda l: l.product_id == cls.product1 ) - self.order_line1.date_start = "2018-01-01" - self.order_line1.product_uom_qty = 12 - pricelist = self.sale.partner_id.property_product_pricelist.id - self.contract = self.env["contract.contract"].create( + cls.order_line1.date_start = "2018-01-01" + cls.order_line1.product_uom_qty = 12 + pricelist = cls.sale.partner_id.property_product_pricelist.id + cls.contract = cls.env["contract.contract"].create( { "name": "Test Contract 2", - "partner_id": self.sale.partner_id.id, + "partner_id": cls.sale.partner_id.id, "pricelist_id": pricelist, "contract_type": "sale", "line_recurrence": True, - "contract_template_id": self.contract_template1.id, + "contract_template_id": cls.contract_template1.id, "contract_line_ids": [ ( 0, 0, { - "product_id": self.product1.id, + "product_id": cls.product1.id, "name": "Services from #START# to #END#", "quantity": 1, - "uom_id": self.product1.uom_id.id, + "uom_id": cls.product1.uom_id.id, "price_unit": 100, "discount": 50, "recurring_rule_type": "monthly", @@ -88,7 +96,7 @@ class TestSaleOrder(TransactionCase): ], } ) - self.contract_line = self.contract.contract_line_ids[0] + cls.contract_line = cls.contract.contract_line_ids[0] def test_compute_is_contract(self): """Sale Order should have is_contract true if one of its lines is @@ -98,7 +106,7 @@ class TestSaleOrder(TransactionCase): def test_action_confirm(self): """It should create a contract for each contract template used in order_line""" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() contracts = self.sale.order_line.mapped("contract_id") self.assertEqual(len(contracts), 2) @@ -142,7 +150,7 @@ class TestSaleOrder(TransactionCase): """It should create a contract for each contract template used in order_line""" self.sale.company_id.create_contract_at_sale_order_confirmation = False - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.assertEqual(len(self.sale.order_line.mapped("contract_id")), 0) self.assertTrue(self.sale.need_contract_creation) @@ -161,14 +169,14 @@ class TestSaleOrder(TransactionCase): def test_sale_contract_count(self): """It should count contracts as many different contract template used in order_line""" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.assertEqual(self.sale.contract_count, 2) def test_onchange_product(self): """It should get recurrence invoicing info to the sale line from its product""" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.assertEqual( self.order_line1.recurring_rule_type, self.product1.recurring_rule_type, @@ -216,7 +224,7 @@ class TestSaleOrder(TransactionCase): def test_sale_order_line_invoice_status(self): """Sale order line for contract product should have nothing to invoice as status""" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.assertEqual(self.order_line1.invoice_status, "no") @@ -226,7 +234,7 @@ class TestSaleOrder(TransactionCase): self.sale.order_line.filtered( lambda line: not line.product_id.is_contract ).unlink() - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.assertEqual(self.sale.invoice_status, "no") @@ -234,7 +242,7 @@ class TestSaleOrder(TransactionCase): """Should not invoice contract product on sale order create invoice""" self.product2.is_contract = False self.product2.invoice_policy = "order" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.sale._create_invoices() self.assertEqual(len(self.sale.invoice_ids), 1) @@ -245,7 +253,7 @@ class TestSaleOrder(TransactionCase): def test_link_contract_invoice_to_sale_order(self): """It should link contract invoice to sale order""" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() invoice = self.order_line1.contract_id.recurring_create_invoice() self.assertTrue(invoice in self.sale.invoice_ids) @@ -257,7 +265,7 @@ class TestSaleOrder(TransactionCase): self.contract_line.date_end = Date.today() + relativedelta(months=4) self.contract_line.is_auto_renew = True self.order_line1.date_start = "2018-06-01" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.assertEqual(self.contract_line.date_end, Date.to_date("2018-05-31")) self.assertFalse(self.contract_line.is_auto_renew) @@ -283,7 +291,7 @@ class TestSaleOrder(TransactionCase): } ) self.order_line1.date_start = "2018-06-01" - self.order_line1.onchange_product() + self.order_line1._compute_auto_renew() self.sale.action_confirm() self.assertFalse(self.contract_line.date_end) self.assertTrue(self.contract_line.is_canceled) @@ -349,7 +357,7 @@ class TestSaleOrder(TransactionCase): "property_contract_template_id": self.contract_template1.id, } ) - self.sale.order_line.onchange_product() + self.sale.order_line._compute_auto_renew() self.sale.action_confirm() contracts = self.sale.order_line.mapped("contract_id") self.assertEqual(len(contracts), 1)