[IMP] product_contract: code improvements

This commit is contained in:
Ilyas
2023-03-22 09:28:04 +01:00
parent 72c7743293
commit f3cb7beb71
5 changed files with 106 additions and 72 deletions

View File

@@ -35,15 +35,19 @@ class ContractLine(models.Model):
for rec in self: for rec in self:
rec.date_start = fields.Date.today() rec.date_start = fields.Date.today()
if rec.product_id.is_contract: if rec.product_id.is_contract:
rec.recurring_rule_type = rec.product_id.recurring_rule_type rec.update(
rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type {
rec.recurring_interval = 1 "recurring_rule_type": rec.product_id.recurring_rule_type,
rec.is_auto_renew = rec.product_id.is_auto_renew "recurring_invoicing_type": rec.product_id.recurring_invoicing_type,
rec.auto_renew_interval = rec.product_id.auto_renew_interval "recurring_interval": 1,
rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type "is_auto_renew": rec.product_id.is_auto_renew,
rec.termination_notice_interval = ( "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 rec.product_id.termination_notice_interval
) ),
rec.termination_notice_rule_type = ( "termination_notice_rule_type": (
rec.product_id.termination_notice_rule_type rec.product_id.termination_notice_rule_type
),
}
) )

View File

@@ -14,7 +14,7 @@ class SaleOrder(models.Model):
need_contract_creation = fields.Boolean(compute="_compute_need_contract_creation") need_contract_creation = fields.Boolean(compute="_compute_need_contract_creation")
@api.constrains("state") @api.constrains("state")
def check_contact_is_not_terminated(self): def _check_contact_is_not_terminated(self):
for rec in self: for rec in self:
if rec.state not in ( if rec.state not in (
"sale", "sale",
@@ -27,8 +27,8 @@ class SaleOrder(models.Model):
@api.depends("order_line.contract_id", "state") @api.depends("order_line.contract_id", "state")
def _compute_need_contract_creation(self): def _compute_need_contract_creation(self):
self.update({"need_contract_creation": False})
for rec in self: for rec in self:
rec.need_contract_creation = False
if rec.state in ("sale", "done"): if rec.state in ("sale", "done"):
line_to_create_contract = rec.order_line.filtered( 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.product_id.is_contract
@@ -64,7 +64,7 @@ class SaleOrder(models.Model):
def action_create_contract(self): def action_create_contract(self):
contract_model = self.env["contract.contract"] contract_model = self.env["contract.contract"]
contracts = self.env["contract.contract"] contracts = []
for rec in self.filtered("is_contract"): for rec in self.filtered("is_contract"):
line_to_create_contract = rec.order_line.filtered( 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.product_id.is_contract
@@ -98,14 +98,14 @@ class SaleOrder(models.Model):
contract = contract_model.create( contract = contract_model.create(
rec._prepare_contract_value(contract_template) rec._prepare_contract_value(contract_template)
) )
contracts |= contract contracts.append(contract)
contract._onchange_contract_template_id() contract._onchange_contract_template_id()
contract._onchange_contract_type() contract._onchange_contract_type()
order_lines.create_contract_line(contract) order_lines.create_contract_line(contract)
order_lines.write({"contract_id": contract.id}) order_lines.write({"contract_id": contract.id})
for line in line_to_update_contract: for line in line_to_update_contract:
line.create_contract_line(line.contract_id) line.create_contract_line(line.contract_id)
return contracts return contract_model.browse(contracts)
def action_confirm(self): def action_confirm(self):
"""If we have a contract in the order, set it up""" """If we have a contract in the order, set it up"""
@@ -117,19 +117,22 @@ class SaleOrder(models.Model):
@api.depends("order_line") @api.depends("order_line")
def _compute_contract_count(self): def _compute_contract_count(self):
for rec in self: for rec in self:
rec.contract_count = len( rec.contract_count = len(rec.order_line.mapped("contract_id"))
rec.order_line.mapped("contract_id").filtered(lambda r: r.active)
)
def action_show_contracts(self): def action_show_contracts(self):
self.ensure_one() 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 = ( contracts = (
self.env["contract.line"] self.env["contract.line"]
.search([("sale_order_line_id", "in", self.order_line.ids)]) .search([("sale_order_line_id", "in", self.order_line.ids)])
.mapped("contract_id") .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 len(contracts) == 1:
# If there is only one contract, open it directly # If there is only one contract, open it directly
action.update( action.update(

View File

@@ -52,10 +52,19 @@ class SaleOrderLine(models.Model):
required=False, required=False,
copy=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( auto_renew_interval = fields.Integer(
default=1, default=1,
string="Renew Every", string="Renew Every",
compute="_compute_auto_renew",
store=True,
readonly=False,
help="Renew every (Days/Week/Month/Year)", help="Renew every (Days/Week/Month/Year)",
) )
auto_renew_rule_type = fields.Selection( auto_renew_rule_type = fields.Selection(
@@ -66,12 +75,15 @@ class SaleOrderLine(models.Model):
("yearly", "Year(s)"), ("yearly", "Year(s)"),
], ],
default="yearly", default="yearly",
compute="_compute_auto_renew",
store=True,
readonly=False,
string="Renewal type", string="Renewal type",
help="Specify Interval for automatic renewal.", help="Specify Interval for automatic renewal.",
) )
@api.constrains("contract_id") @api.constrains("contract_id")
def check_contact_is_not_terminated(self): def _check_contact_is_not_terminated(self):
for rec in self: for rec in self:
if ( if (
rec.order_id.state not in ("sale", "done", "cancel") rec.order_id.state not in ("sale", "done", "cancel")
@@ -108,8 +120,8 @@ class SaleOrderLine(models.Model):
) )
return date_end return date_end
@api.onchange("product_id") @api.depends("product_id")
def onchange_product(self): def _compute_auto_renew(self):
for rec in self: for rec in self:
if rec.product_id.is_contract: if rec.product_id.is_contract:
rec.product_uom_qty = rec.product_id.default_qty rec.product_uom_qty = rec.product_id.default_qty
@@ -248,9 +260,8 @@ class SaleOrderLine(models.Model):
) )
def _compute_invoice_status(self): def _compute_invoice_status(self):
res = super(SaleOrderLine, self)._compute_invoice_status() res = super()._compute_invoice_status()
for line in self.filtered("contract_id"): self.filtered("contract_id").update({"invoice_status": "no"})
line.invoice_status = "no"
return res return res
def invoice_line_create(self, invoice_id, qty): def invoice_line_create(self, invoice_id, qty):

View File

@@ -3,15 +3,23 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase from odoo.tests.common import SavepointCase
class TestProductTemplate(TransactionCase): class TestProductTemplate(SavepointCase):
def setUp(self): @classmethod
super(TestProductTemplate, self).setUp() def setUpClass(cls):
self.service_product = self.env.ref("product.product_product_1") super().setUpClass()
self.consu_product = self.env.ref("product.product_product_5") cls.env = cls.env(
self.contract = self.env["contract.template"].create({"name": "Test"}) 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): def test_change_is_contract(self):
"""It should verify that the property_contract_template_id """It should verify that the property_contract_template_id

View File

@@ -6,19 +6,27 @@ from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.fields import Date from odoo.fields import Date
from odoo.tests.common import TransactionCase from odoo.tests.common import SavepointCase
class TestSaleOrder(TransactionCase): class TestSaleOrder(SavepointCase):
def setUp(self): @classmethod
super(TestSaleOrder, self).setUp() def setUpClass(cls):
self.product1 = self.env.ref("product.product_product_1") super().setUpClass()
self.product2 = self.env.ref("product.product_product_2") cls.env = cls.env(
self.sale = self.env.ref("sale.sale_order_2") context=dict(
self.contract_template1 = self.env["contract.template"].create( 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"} {"name": "Template 1"}
) )
self.contract_template2 = self.env["contract.template"].create( cls.contract_template2 = cls.env["contract.template"].create(
{ {
"name": "Template 2", "name": "Template 2",
"contract_line_ids": [ "contract_line_ids": [
@@ -26,10 +34,10 @@ class TestSaleOrder(TransactionCase):
0, 0,
0, 0,
{ {
"product_id": self.product2.id, "product_id": cls.product2.id,
"name": "Services from #START# to #END#", "name": "Services from #START# to #END#",
"quantity": 1, "quantity": 1,
"uom_id": self.product2.uom_id.id, "uom_id": cls.product2.uom_id.id,
"price_unit": 100, "price_unit": 100,
"discount": 50, "discount": 50,
"recurring_rule_type": "yearly", "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, "is_contract": True,
"default_qty": 12, "default_qty": 12,
"recurring_rule_type": "monthlylastday", "recurring_rule_type": "monthlylastday",
"recurring_invoicing_type": "post-paid", "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, "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( cls.order_line1 = cls.sale.order_line.filtered(
lambda l: l.product_id == self.product1 lambda l: l.product_id == cls.product1
) )
self.order_line1.date_start = "2018-01-01" cls.order_line1.date_start = "2018-01-01"
self.order_line1.product_uom_qty = 12 cls.order_line1.product_uom_qty = 12
pricelist = self.sale.partner_id.property_product_pricelist.id pricelist = cls.sale.partner_id.property_product_pricelist.id
self.contract = self.env["contract.contract"].create( cls.contract = cls.env["contract.contract"].create(
{ {
"name": "Test Contract 2", "name": "Test Contract 2",
"partner_id": self.sale.partner_id.id, "partner_id": cls.sale.partner_id.id,
"pricelist_id": pricelist, "pricelist_id": pricelist,
"contract_type": "sale", "contract_type": "sale",
"line_recurrence": True, "line_recurrence": True,
"contract_template_id": self.contract_template1.id, "contract_template_id": cls.contract_template1.id,
"contract_line_ids": [ "contract_line_ids": [
( (
0, 0,
0, 0,
{ {
"product_id": self.product1.id, "product_id": cls.product1.id,
"name": "Services from #START# to #END#", "name": "Services from #START# to #END#",
"quantity": 1, "quantity": 1,
"uom_id": self.product1.uom_id.id, "uom_id": cls.product1.uom_id.id,
"price_unit": 100, "price_unit": 100,
"discount": 50, "discount": 50,
"recurring_rule_type": "monthly", "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): def test_compute_is_contract(self):
"""Sale Order should have is_contract true if one of its lines is """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): def test_action_confirm(self):
"""It should create a contract for each contract template used in """It should create a contract for each contract template used in
order_line""" order_line"""
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
contracts = self.sale.order_line.mapped("contract_id") contracts = self.sale.order_line.mapped("contract_id")
self.assertEqual(len(contracts), 2) self.assertEqual(len(contracts), 2)
@@ -142,7 +150,7 @@ class TestSaleOrder(TransactionCase):
"""It should create a contract for each contract template used in """It should create a contract for each contract template used in
order_line""" order_line"""
self.sale.company_id.create_contract_at_sale_order_confirmation = False 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.sale.action_confirm()
self.assertEqual(len(self.sale.order_line.mapped("contract_id")), 0) self.assertEqual(len(self.sale.order_line.mapped("contract_id")), 0)
self.assertTrue(self.sale.need_contract_creation) self.assertTrue(self.sale.need_contract_creation)
@@ -161,14 +169,14 @@ class TestSaleOrder(TransactionCase):
def test_sale_contract_count(self): def test_sale_contract_count(self):
"""It should count contracts as many different contract template used """It should count contracts as many different contract template used
in order_line""" in order_line"""
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
self.assertEqual(self.sale.contract_count, 2) self.assertEqual(self.sale.contract_count, 2)
def test_onchange_product(self): def test_onchange_product(self):
"""It should get recurrence invoicing info to the sale line from """It should get recurrence invoicing info to the sale line from
its product""" its product"""
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.assertEqual( self.assertEqual(
self.order_line1.recurring_rule_type, self.order_line1.recurring_rule_type,
self.product1.recurring_rule_type, self.product1.recurring_rule_type,
@@ -216,7 +224,7 @@ class TestSaleOrder(TransactionCase):
def test_sale_order_line_invoice_status(self): def test_sale_order_line_invoice_status(self):
"""Sale order line for contract product should have nothing to """Sale order line for contract product should have nothing to
invoice as status""" invoice as status"""
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
self.assertEqual(self.order_line1.invoice_status, "no") self.assertEqual(self.order_line1.invoice_status, "no")
@@ -226,7 +234,7 @@ class TestSaleOrder(TransactionCase):
self.sale.order_line.filtered( self.sale.order_line.filtered(
lambda line: not line.product_id.is_contract lambda line: not line.product_id.is_contract
).unlink() ).unlink()
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
self.assertEqual(self.sale.invoice_status, "no") self.assertEqual(self.sale.invoice_status, "no")
@@ -234,7 +242,7 @@ class TestSaleOrder(TransactionCase):
"""Should not invoice contract product on sale order create invoice""" """Should not invoice contract product on sale order create invoice"""
self.product2.is_contract = False self.product2.is_contract = False
self.product2.invoice_policy = "order" self.product2.invoice_policy = "order"
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
self.sale._create_invoices() self.sale._create_invoices()
self.assertEqual(len(self.sale.invoice_ids), 1) self.assertEqual(len(self.sale.invoice_ids), 1)
@@ -245,7 +253,7 @@ class TestSaleOrder(TransactionCase):
def test_link_contract_invoice_to_sale_order(self): def test_link_contract_invoice_to_sale_order(self):
"""It should link contract invoice to sale order""" """It should link contract invoice to sale order"""
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
invoice = self.order_line1.contract_id.recurring_create_invoice() invoice = self.order_line1.contract_id.recurring_create_invoice()
self.assertTrue(invoice in self.sale.invoice_ids) 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.date_end = Date.today() + relativedelta(months=4)
self.contract_line.is_auto_renew = True self.contract_line.is_auto_renew = True
self.order_line1.date_start = "2018-06-01" self.order_line1.date_start = "2018-06-01"
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
self.assertEqual(self.contract_line.date_end, Date.to_date("2018-05-31")) self.assertEqual(self.contract_line.date_end, Date.to_date("2018-05-31"))
self.assertFalse(self.contract_line.is_auto_renew) 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.date_start = "2018-06-01"
self.order_line1.onchange_product() self.order_line1._compute_auto_renew()
self.sale.action_confirm() self.sale.action_confirm()
self.assertFalse(self.contract_line.date_end) self.assertFalse(self.contract_line.date_end)
self.assertTrue(self.contract_line.is_canceled) self.assertTrue(self.contract_line.is_canceled)
@@ -349,7 +357,7 @@ class TestSaleOrder(TransactionCase):
"property_contract_template_id": self.contract_template1.id, "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() self.sale.action_confirm()
contracts = self.sale.order_line.mapped("contract_id") contracts = self.sale.order_line.mapped("contract_id")
self.assertEqual(len(contracts), 1) self.assertEqual(len(contracts), 1)