[MIG] product_contract: Migration to 14.0

This commit is contained in:
Mourad
2021-03-09 16:50:25 +01:00
committed by Ilyas
parent 1d0c280fe5
commit b793cf6356
9 changed files with 65 additions and 70 deletions

View File

@@ -7,6 +7,7 @@ from collections import namedtuple
from datetime import timedelta from datetime import timedelta
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
from odoo import fields from odoo import fields
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
@@ -2370,6 +2371,7 @@ class TestContract(TestContractBase):
to_date("2018-02-13"), to_date("2018-02-13"),
) )
@freeze_time("2020-01-01 00:00:00")
def test_recurrency_propagation(self): def test_recurrency_propagation(self):
# Existing contract # Existing contract
vals = { vals = {

View File

@@ -4,7 +4,7 @@
{ {
"name": "Recurring - Product Contract", "name": "Recurring - Product Contract",
"version": "13.0.1.0.0", "version": "14.0.1.0.0",
"category": "Contract Management", "category": "Contract Management",
"license": "AGPL-3", "license": "AGPL-3",
"author": "LasLabs, " "ACSONE SA/NV, " "Odoo Community Association (OCA)", "author": "LasLabs, " "ACSONE SA/NV, " "Odoo Community Association (OCA)",

View File

@@ -65,7 +65,7 @@ class ProductTemplate(models.Model):
def write(self, vals): def write(self, vals):
if "is_contract" in vals and vals["is_contract"] is False: if "is_contract" in vals and vals["is_contract"] is False:
for company in self.env["res.company"].search([]): for company in self.env["res.company"].search([]):
self.with_context(force_company=company.id).write( self.with_company(company).write(
{"property_contract_template_id": False} {"property_contract_template_id": False}
) )
super().write(vals) super().write(vals)

View File

@@ -16,15 +16,11 @@ class SaleOrder(models.Model):
@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 ( if rec.state not in (
rec.state
not in (
"sale", "sale",
"done", "done",
"cancel", "cancel",
) ) and rec.order_line.filtered("contract_id.is_terminated"):
and rec.order_line.filtered("contract_id.is_terminated")
):
raise ValidationError( raise ValidationError(
_("You can't upsell or downsell a terminated contract") _("You can't upsell or downsell a terminated contract")
) )
@@ -81,8 +77,8 @@ class SaleOrder(models.Model):
) )
contract_templates = self.env["contract.template"] contract_templates = self.env["contract.template"]
for order_line in line_to_create_contract: for order_line in line_to_create_contract:
contract_template = order_line.product_id.with_context( contract_template = order_line.product_id.with_company(
force_company=rec.company_id.id rec.company_id
).property_contract_template_id ).property_contract_template_id
if not contract_template: if not contract_template:
raise ValidationError( raise ValidationError(
@@ -94,8 +90,8 @@ class SaleOrder(models.Model):
contract_templates |= contract_template contract_templates |= contract_template
for contract_template in contract_templates: for contract_template in contract_templates:
order_lines = line_to_create_contract.filtered( order_lines = line_to_create_contract.filtered(
lambda r, template=contract_template: r.product_id.with_context( lambda r, template=contract_template: r.product_id.with_company(
force_company=r.order_id.company_id.id r.order_id.company_id
).property_contract_template_id ).property_contract_template_id
== template == template
) )
@@ -112,7 +108,7 @@ class SaleOrder(models.Model):
return contracts return 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"""
self.filtered( self.filtered(
lambda order: (order.company_id.create_contract_at_sale_order_confirmation) lambda order: (order.company_id.create_contract_at_sale_order_confirmation)
).action_create_contract() ).action_create_contract()
@@ -127,7 +123,7 @@ class SaleOrder(models.Model):
def action_show_contracts(self): def action_show_contracts(self):
self.ensure_one() self.ensure_one()
action = self.env.ref("contract.action_customer_contract").read()[0] action = self.env.ref("contract.action_customer_contract").sudo().read()[0]
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)])

View File

@@ -84,8 +84,8 @@ class SaleOrderLine(models.Model):
@api.depends("product_id") @api.depends("product_id")
def _compute_contract_template_id(self): def _compute_contract_template_id(self):
for rec in self: for rec in self:
rec.contract_template_id = rec.product_id.with_context( rec.contract_template_id = rec.product_id.with_company(
force_company=rec.order_id.company_id.id rec.order_id.company_id
).property_contract_template_id ).property_contract_template_id
def _get_auto_renew_rule_type(self): def _get_auto_renew_rule_type(self):
@@ -95,9 +95,21 @@ class SaleOrderLine(models.Model):
return "monthly" return "monthly"
return self.recurring_rule_type return self.recurring_rule_type
def _get_date_end(self):
self.ensure_one()
contract_line_model = self.env["contract.line"]
date_end = (
self.date_start
+ contract_line_model.get_relative_delta(
self._get_auto_renew_rule_type(),
int(self.product_uom_qty),
)
- relativedelta(days=1)
)
return date_end
@api.onchange("product_id") @api.onchange("product_id")
def onchange_product(self): def onchange_product(self):
contract_line_model = self.env["contract.line"]
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
@@ -105,14 +117,7 @@ class SaleOrderLine(models.Model):
rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type
rec.date_start = rec.date_start or fields.Date.today() rec.date_start = rec.date_start or fields.Date.today()
rec.date_end = ( rec.date_end = rec._get_date_end()
rec.date_start
+ contract_line_model.get_relative_delta(
rec._get_auto_renew_rule_type(),
int(rec.product_uom_qty),
)
- relativedelta(days=1)
)
rec.is_auto_renew = rec.product_id.is_auto_renew rec.is_auto_renew = rec.product_id.is_auto_renew
if rec.is_auto_renew: if rec.is_auto_renew:
rec.auto_renew_interval = rec.product_id.auto_renew_interval rec.auto_renew_interval = rec.product_id.auto_renew_interval
@@ -120,19 +125,25 @@ class SaleOrderLine(models.Model):
@api.onchange("date_start", "product_uom_qty", "recurring_rule_type") @api.onchange("date_start", "product_uom_qty", "recurring_rule_type")
def onchange_date_start(self): def onchange_date_start(self):
contract_line_model = self.env["contract.line"]
for rec in self.filtered("product_id.is_contract"): for rec in self.filtered("product_id.is_contract"):
if not rec.date_start: rec.date_end = rec._get_date_end() if rec.date_start else False
rec.date_end = False
else: def _get_contract_line_qty(self):
rec.date_end = ( """Returns the quantity to be put on new contract lines."""
rec.date_start self.ensure_one()
+ contract_line_model.get_relative_delta( # The quantity on the generated contract line is 1, as it
rec._get_auto_renew_rule_type(), # correspond to the most common use cases:
int(rec.product_uom_qty), # - quantity on the SO line = number of periods sold and unit
) # price the price of one period, so the
- relativedelta(days=1) # total amount of the SO corresponds to the planned value
) # of the contract; in this case the quantity on the contract
# line must be 1
# - quantity on the SO line = number of hours sold,
# automatic invoicing of the actual hours through a variable
# quantity formula, in which case the quantity on the contract
# line is not used
# Other use cases are easy to implement by overriding this method.
return 1.0
def _prepare_contract_line_values( def _prepare_contract_line_values(
self, contract, predecessor_contract_line_id=False self, contract, predecessor_contract_line_id=False
@@ -157,19 +168,7 @@ class SaleOrderLine(models.Model):
"sequence": self.sequence, "sequence": self.sequence,
"product_id": self.product_id.id, "product_id": self.product_id.id,
"name": self.name, "name": self.name,
# The quantity on the generated contract line is 1, as it "quantity": self._get_contract_line_qty(),
# correspond to the most common use cases:
# - quantity on the SO line = number of periods sold and unit
# price the price of one period, so the
# total amount of the SO corresponds to the planned value
# of the contract; in this case the quantity on the contract
# line must be 1
# - quantity on the SO line = number of hours sold,
# automatic invoicing of the actual hours through a variable
# quantity formula, in which case the quantity on the contract
# line is not used
# Other use cases are easy to implement by overriding this method.
"quantity": 1.0,
"uom_id": self.product_uom.id, "uom_id": self.product_uom.id,
"price_unit": self.price_unit, "price_unit": self.price_unit,
"discount": self.discount, "discount": self.discount,

View File

@@ -4,7 +4,7 @@
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from odoo.exceptions import 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 TransactionCase
@@ -39,7 +39,7 @@ class TestSaleOrder(TransactionCase):
], ],
} }
) )
self.product1.with_context(force_company=self.sale.company_id.id).write( self.product1.with_company(self.sale.company_id).write(
{ {
"is_contract": True, "is_contract": True,
"default_qty": 12, "default_qty": 12,
@@ -48,7 +48,7 @@ class TestSaleOrder(TransactionCase):
"property_contract_template_id": self.contract_template1.id, "property_contract_template_id": self.contract_template1.id,
} }
) )
self.product2.with_context(force_company=self.sale.company_id.id).write( self.product2.with_company(self.sale.company_id).write(
{ {
"is_contract": True, "is_contract": True,
"property_contract_template_id": self.contract_template2.id, "property_contract_template_id": self.contract_template2.id,
@@ -116,26 +116,16 @@ class TestSaleOrder(TransactionCase):
other_company = self.env["res.company"].create( other_company = self.env["res.company"].create(
{"name": "other company", "parent_id": self.sale.company_id.id} {"name": "other company", "parent_id": self.sale.company_id.id}
) )
with self.assertRaises(UserError):
self.sale.company_id = other_company self.sale.company_id = other_company
with self.assertRaises(ValidationError):
self.sale.action_confirm() self.sale.action_confirm()
def test_change_sale_company_2(self): def test_change_sale_company_2(self):
"""Contract company must be the sale order company.""" """Contract company must be the sale order company."""
self.assertTrue(self.sale.company_id) self.assertTrue(self.sale.company_id)
other_company = self.env["res.company"].create(
{"name": "other company", "parent_id": self.sale.company_id.id}
)
self.product1.with_context(
force_company=other_company.id
).property_contract_template_id = self.contract_template1
self.product2.with_context(
force_company=other_company.id
).property_contract_template_id = self.contract_template2
self.sale.company_id = other_company
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(contracts.mapped("company_id"), other_company) self.assertEqual(contracts.mapped("company_id"), self.sale.company_id)
def test_sale_order_invoice_status(self): def test_sale_order_invoice_status(self):
""" """
@@ -353,7 +343,7 @@ class TestSaleOrder(TransactionCase):
def test_order_lines_with_the_same_contract_template(self): def test_order_lines_with_the_same_contract_template(self):
"""It should create one contract with two lines grouped by contract """It should create one contract with two lines grouped by contract
template""" template"""
self.product2.with_context(force_company=self.sale.company_id.id).write( self.product2.with_company(self.sale.company_id).write(
{ {
"is_contract": True, "is_contract": True,
"property_contract_template_id": self.contract_template1.id, "property_contract_template_id": self.contract_template1.id,

View File

@@ -1 +1,2 @@
# generated from manifests external_dependencies # generated from manifests external_dependencies
python-dateutil

View File

@@ -0,0 +1 @@
../../../../product_contract

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)